<!DOCTYPE html>

<html lang="zh-cn">

<head>
    <meta charset="utf-8">
    <title>StencilTest</title>
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <script src="three.js"></script>
    <script src="OrbitControls.js"></script>
    <script>
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // 控制器
        new THREE.OrbitControls(camera, renderer.domElement);

        // 光源
        var amlight = new THREE.AmbientLight(0xffffff, 0.4);
        var dirlight = new THREE.DirectionalLight(0xffffff, 0.6);

        dirlight.position.set(1, 2, 3);

        scene.add(amlight);
        scene.add(dirlight);

        // 模型1
        var mesh1 = null;

        var loader = new THREE.JSONLoader();
        loader.load('AMY.json', geometry => {
            var material = new THREE.MeshPhongMaterial({ color: 0xffff00 });
            mesh1 = new THREE.Mesh(geometry, material);
            scene.add(mesh1);
        });

        // 模型2
        var mesh2 = null;

        loader.load('ATWO.json', geometry => {
            var material = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
            mesh2 = new THREE.Mesh(geometry, material);
            mesh2.rotation.x = Math.PI / 2;
            scene.add(mesh2);
        });

        camera.position.z = 500;

        renderer.autoClear = false;

        // 线框
        var wireframeMaterial = new THREE.MeshBasicMaterial({
            wireframe: true
        });

        var context = renderer.getContext();
        var state = renderer.state;

        // three.js有bug
        state.buffers.stencil.setTest = function () {

        };

        var animate = function () {
            requestAnimationFrame(animate);

            if (!mesh1 || !mesh2) {
                return;
            }

            renderer.clear();

            // 绘制模板
            state.enable(context.STENCIL_TEST);
            state.buffers.stencil.setTest(true);
            state.buffers.stencil.setClear(0x00);

            state.buffers.color.setMask(false);
            state.buffers.depth.setMask(false);
            state.buffers.stencil.setMask(0xff);

            state.buffers.color.setLocked(true);
            state.buffers.depth.setLocked(true);
            state.buffers.stencil.setLocked(true);

            state.buffers.stencil.setOp(context.REPLACE, context.REPLACE, context.REPLACE);

            scene.remove(mesh1);
            scene.remove(mesh2);
            scene.add(mesh1);
            state.buffers.stencil.setLocked(false);
            state.buffers.stencil.setMask(0b1);
            state.buffers.stencil.setLocked(true);
            state.buffers.stencil.setFunc(context.ALWAYS, 0b1, 0b1);
            renderer.render(scene, camera);

            scene.remove(mesh1);
            scene.remove(mesh2);
            scene.add(mesh2);
            state.buffers.stencil.setLocked(false);
            state.buffers.stencil.setMask(0b10);
            state.buffers.stencil.setLocked(true);
            state.buffers.stencil.setFunc(context.ALWAYS, 0b10, 0b10);
            renderer.render(scene, camera);

            scene.remove(mesh1);
            scene.remove(mesh2);
            scene.add(mesh1);
            scene.add(mesh2);

            // 绘制相交物体
            state.buffers.color.setLocked(false);
            state.buffers.depth.setLocked(false);
            state.buffers.stencil.setLocked(false);

            state.buffers.color.setMask(true);
            state.buffers.depth.setMask(true);
            state.buffers.stencil.setMask(0xff);

            state.buffers.stencil.setLocked(true);

            state.buffers.stencil.setOp(context.KEEP, context.KEEP, context.KEEP);
            state.buffers.stencil.setFunc(context.EQUAL, 3, 0b11);

            renderer.render(scene, camera);

            // 绘制线框
            state.buffers.stencil.setFunc(context.NOTEQUAL, 3, 0b11);

            scene.overrideMaterial = wireframeMaterial;
            renderer.render(scene, camera);
            scene.overrideMaterial = null;

            // 还原初始状态
            state.buffers.stencil.setLocked(false);
            state.disable(context.STENCIL_TEST);
        };

        animate();
    </script>
</body>

</html>